package pwd.allen.springboot;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.stereotype.Component;

/**
 * 消息从 producer 到 rabbitmq broker有一个 confirmCallback 确认模式。
 * 消息从 exchange 到 queue 投递失败有一个 returnCallback 退回模式。
 *
 * TODO 是否需要配置 spring.rabbitmq.publisher-confirms=true
 *
 * @author pwdan
 * @create 2024-09-05 9:30
 **/
@Slf4j
@Component
public class MyConfirmCallback implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback {

    /**
     * 消息只要被 rabbitmq broker 接收到就会触发 confirmCallback 回调
     * 如果消息投递失败，ack=false并且cause 不为空，表示失败原因
     * 但消息被 broker 接收到只能表示已经到达 MQ服务器，并不能保证消息一定会被投递到目标 queue 里
 }
     *
     * @param correlationData 内部只有一个 id 属性，用来表示当前消息的唯一性
     * @param ack true for ack, false for nack
     * @param cause An optional cause, for nack, when available, otherwise null.
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause){
        if (!ack) {
            log.error("消息发送异常：{}", cause);
        } else {
            log.info("发送者爸爸已经收到确认，correlationData={} ,ack={}, cause={}", correlationData.getId(), ack, cause);
        }

    }

    /**
     * 如果消息未能投递到目标 queue 里将触发回调 returnCallback ，一旦向 queue 投递消息未成功，这里一般会记录下当前消息的详细投递数据，方便后续做重发或者补偿等操作
     *
     * @param message the returned message.
     * @param replyCode the reply code.
     * @param replyText the reply text.
     * @param exchange the exchange.
     * @param routingKey the routing key.
     */
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        log.error("消息发送失败，replyCode={}, replyText={}, exchange={}, routingKey={}", replyCode, replyText, exchange, routingKey);
    }
}



